home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 3: CDPD 3 / Almathera Ten on Ten - Disc 3: CDPD3.iso / scope / 001-025 / scopedisk8 / qint / qint.c next >
C/C++ Source or Header  |  1995-03-18  |  8KB  |  284 lines

  1.  
  2. /*
  3.  *  QINT.C
  4.  *
  5.  *  Prioritized Interrupt scheme based on exceptions (and therefore
  6.  *  standard signals).
  7.  *
  8.  *  NOTE the following bugs in EXEC exception handling:
  9.  *    -If you ever use Forbid()/Permit() pair, An exception which comes
  10.  *     in within the pair will not get processed after the Permit()
  11.  *     until one of several system calls is made to force a re-evaluation.
  12.  *
  13.  *    -We cannot simply return a mask at the end of the exception
  14.  *     handler because if a signal comes in after the exception occurs
  15.  *     but before we return, the same problem as with Forbid()/Permit()
  16.  *     comes up.
  17.  *
  18.  *  Calling SetExcept() while NOT Forbid()n appears to fix the problem.
  19.  */
  20.  
  21. #include <exec/types.h>     /*  Includes.  You might have to add some   */
  22. #include <exec/nodes.h>     /*  If I missed any.                */
  23. #include <exec/lists.h>
  24. #include <exec/tasks.h>
  25.  
  26. typedef unsigned char    ubyte;
  27. typedef unsigned short    uword;
  28. typedef unsigned long    ulong;
  29. typedef struct Task    TASK;
  30. typedef struct Node    NODE;
  31. typedef struct List    LIST;
  32. typedef void        (*FPTR)();
  33.  
  34. extern TASK *FindTask();
  35.  
  36. #define QINT    struct _QINT
  37.  
  38. QINT {                /*    32 bytes total        */
  39.     NODE    Node;        /*    14 bytes        */
  40.     FPTR    vector;        /*    Function to call    */
  41.     long    sigmask;        /*    signal mask (1 bit set) */
  42.     long    arg;        /*    argument to handler    */
  43.     ubyte   filler2[6];
  44. };
  45.  
  46. /*
  47.  *  Note: Since -128 is the lowest priority possible, setting an
  48.  *  exception's priority to -128 means it will never occur.
  49.  */
  50.  
  51. static char QPri = -128;   /*  Current process Q interrupt priority       */
  52. static QINT QInt[32];       /*  Q interrupts which are really exceptions    */
  53. static LIST QList;       /*  List of pending Q interrupts           */
  54. static APTR QSaveExcept;
  55. static short QInts;
  56. static short QInHan;       /*  Currently in the exception queue handler    */
  57.  
  58. void except();
  59. void QInit();
  60.  
  61. #asm
  62.         ;    _EXCEPT
  63.         ;
  64.         ;    Exception handler.
  65.         ;
  66.         ;    ALL data and address registers are saved by EXEC.  D0
  67.         ;    holds the exceptions that occured on entry, and A1
  68.         ;    holds the exception data frame (which we do not use,
  69.         ;    but need to save in case there are exceptions that
  70.         ;    we do not own).
  71.  
  72.         public  _LVOForbid
  73.         public  _LVOPermit
  74.         public  _LVOEnqueue
  75.         public  _LVOSetSignal
  76.         public  _geta4        ;Aztec: Load proper address reg.
  77.         public  _QSaveExcept
  78.         public  _QInHan
  79.  
  80. _except:
  81.         move.l    A1,-(sp)        ;save except data segment
  82.         move.l    4,A6        ;A6 = Exec Base
  83.         move.l    D0,D6        ;D6 = Exception Bit Mask
  84.         jsr     _geta4        ;get global base register (Aztec small code)
  85.         ;;sub.w      #1,_QLevel      ;level down!
  86.         ;;bpl      .ex0
  87.         ;;                  ;   STACKING LIMIT REACHED
  88.         ;;add.w      #1,_QLevel      ;down too far!
  89.         ;;add.l      #1,_QError      ;mark it
  90.         ;;jsr      _LVOForbid(A6)  ;Reload all exceptions that occured
  91.         ;;move.l      D6,D0
  92.         ;;move.l      D6,D1
  93.         ;;jsr      _LVOSetSignal(A6)
  94.         ;;jsr      _LVOPermit(A6)
  95.         ;;move.l      D6,D0       ;Reenable all exceptions that
  96.         ;;                  ; occured by returning the mask in D0
  97.         ;;addq.l      #4,sp       ;restore stack frame
  98.         ;;rts
  99.  
  100.         ;    Queue any exceptions which are interrupts.  Exceptions
  101.         ;    for interrupts which are queued are NOT reenabled until
  102.         ;    they are actually run.
  103.         ;
  104.         ;    Note that in the loop we must loop to .ex2 to decrement
  105.         ;    D4, which doesn't occur when we find a '1'.  The Z bit
  106.         ;    must be set when we loop to .ex2
  107.  
  108. .ex0        moveq.l    #31,D4        ;D4 = BIT NUMBER
  109. .ex1        btst.l    D4,D6        ; test bits
  110. .ex2        dbne    D4,.ex1     ; until found a '1'
  111.         beq     .ex10        ;or loop exhausted (D4 == -1)
  112.  
  113.         move.l    D4,D5        ;Calculate address of QINT.
  114.         asl.l    #5,D5        ;D5 = index * sizeof(QINT)
  115.         add.l    #_QInt,D5    ;     + Address
  116.         move.l    D5,A3        ;A3 = QINT address
  117.         tst.l    14(A3)          ;Is this exception vectored?
  118.         beq     .ex2        ;no, somebody else owns it
  119.  
  120. .ex3        bclr.l    D4,D6        ;clear exception bit.
  121.         jsr     _LVOForbid(A6)  ;Important operation!
  122.         move.l    A3,A1        ;A1 = node
  123.         lea.l    _QList,A0    ;A0 = List base
  124.         move.b    #5,8(A1)        ;mark as being queued
  125.         jsr     _LVOEnqueue(A6)
  126.         jsr     _LVOPermit(A6)  ;enable exceptions
  127.         clr.w    D7        ;Force Z cc set.
  128.         bra     .ex2
  129.  
  130.         ;    Call the handler.  NOTE that handler() need only
  131.         ;    save/restore D6.  Both Lattice and Aztec will do this.
  132.  
  133. .ex10        tst.w    _QInHan     ;no need to call handler?
  134.         bne     .ex11
  135.         bsr     _handler    ;call handler
  136. .ex11        move.l    D6,D0        ;D0 = exception mask
  137.         beq     .ex12        ;we processed all exceptions
  138.         move.l    _QSaveExcept,A0 ;somebody else owns some exceptions
  139.         move.l    (sp)+,A1        ;restore exception data pointer
  140.         ;;add.w      #1,_QLevel
  141.         jmp     (A0)            ;call him with remaining exceptions.
  142. .ex12        addq.l    #4,sp        ;from push at top
  143.         ;;add.w      #1,_QLevel
  144.         rts
  145.  
  146. #endasm
  147.  
  148. /*
  149.  *  Exception Queue handler!
  150.  *
  151.  *  Note:   The places I set QInHan may appear to be strange, but keep
  152.  *        in mind that exceptions will not occur while we are Forbid()n.
  153.  */
  154.  
  155. static
  156. void
  157. handler()
  158. {
  159.     register QINT *qint;
  160.     register char savepri;
  161.  
  162.     QInHan = 1;
  163.     Forbid();
  164.     while ((qint = (QINT *)QList.lh_Head) != (QINT *)&QList.lh_Tail) {
  165.     if (qint->Node.ln_Pri <= QPri)  /*  priority not high enough    */
  166.         break;
  167.     savepri = QPri;         /*  save old priority        */
  168.     Remove(qint);                   /*  remove from queue           */
  169.     qint->Node.ln_Type = 0;     /*  mark as such        */
  170.     QPri = qint->Node.ln_Pri;    /*  up the priority        */
  171.     Permit();
  172.     (*qint->vector)(qint->arg);     /*  call handler                */
  173.     QPri = savepri;         /*  restore priority        */
  174.     if (qint->vector)               /*  reenable if still exists    */
  175.         SetExcept(qint->sigmask, qint->sigmask);
  176.     Forbid();
  177.     }
  178.     QInHan = 0;
  179.     Permit();
  180.  
  181.     /*
  182.      *    Exceptions are not checked on return, so we must call SetExcept()
  183.      *    here to 'force' a check (i.e. the exception signal comes in before
  184.      *    the exception handler returns).
  185.      */
  186.  
  187.     SetExcept(0,0);
  188. }
  189.  
  190. static
  191. void
  192. QInit()
  193. {
  194.     NewList(&QList);
  195. }
  196.  
  197. /*
  198.  *        ----------------------------------------------------------
  199.  *
  200.  *  SETQVECTOR()
  201.  *
  202.  *  Vector a signal at a specified priority.  Setting the vector to NULL
  203.  *  Removes the Q Interrupt.  Exceptions are automatically enabled or
  204.  *  disabled for the signal bit.
  205.  */
  206.  
  207. FPTR
  208. SetQVector(signo, vector, arg, pri)
  209. FPTR vector;
  210. long arg;
  211. long signo;
  212. char pri;
  213. {
  214.     register QINT *qint = QInt + signo;
  215.     register long sigmask = 1 << signo;
  216.     register FPTR oldvector;
  217.  
  218.     Forbid();
  219.     if (!QList.lh_Head)                         /*  Init (first call)   */
  220.     QInit();
  221.     oldvector = qint->vector;
  222.     if (!vector) {                              /*  kill the Q int      */
  223.     if (oldvector) {                        /*  one less            */
  224.         SetExcept(0, sigmask);              /*  disable exception   */
  225.         if (qint->Node.ln_Type == 5) {      /*  If queued to go     */
  226.         Remove(qint);                   /*   Remove from queue  */
  227.         qint->Node.ln_Type = 0;
  228.         }
  229.         if (--QInts == 0)                   /*  No more Q Ints      */
  230.         FindTask(NULL)->tc_ExceptCode = QSaveExcept;
  231.     }
  232.     } else {
  233.     if (!oldvector) {                       /*  New Interrupt?      */
  234.         if (++QInts == 1) {                 /*  First Interrupt?    */
  235.         QSaveExcept = FindTask(NULL)->tc_ExceptCode;
  236.         FindTask(NULL)->tc_ExceptCode = (APTR)except;
  237.         }
  238.     }
  239.     qint->arg = arg;
  240.     qint->Node.ln_Pri = pri;        /*  set priority    */
  241.     qint->sigmask = sigmask;        /*  set signal mask    */
  242.     SetExcept(sigmask, sigmask);            /*  enable exception    */
  243.     }
  244.     qint->vector = vector;            /*  set vector        */
  245.     Permit();                                   /*  reenable exceptions */
  246.     SetExcept(0,0);                             /*  force mask check    */
  247.     return(oldvector);
  248. }
  249.  
  250. /*
  251.  *  SETQPRI()
  252.  *
  253.  *  Set the task's Q priority
  254.  *
  255.  *  Note:  I *could* use a Forbid()/Permit() pair, but due to the
  256.  *  exception handling bug noted above, I would then have to do a
  257.  *  SetExcept(0,0).
  258.  */
  259.  
  260. char
  261. SetQPri(newpri)
  262. char newpri;
  263. {
  264.     char oldpri;
  265.  
  266.     if (!QList.lh_Head)     /*  Init (first call)   */
  267.     QInit();
  268.     Disable();              /*  Modify the priority */
  269.     oldpri = QPri;
  270.     QPri = newpri;
  271.     Enable();
  272.  
  273.     /*
  274.      *    Don't bother calling the handler unless there is something
  275.      *    queued.
  276.      */
  277.  
  278.     if (QList.lh_Head != (APTR)&QList.lh_Tail)
  279.     handler();
  280.  
  281.     return(oldpri);
  282. }
  283.  
  284.